// frontend/utils/performance-monitor.js
/**
 * 前端性能监控工具 📊
 * 
 * 监控和收集前端性能指标，包括加载时间、渲染性能、API调用性能等
 */

class PerformanceMonitor {
  /**
   * 初始化性能监控器
   * @param {Object} options - 配置选项
   * @param {boolean} options.autoStart - 是否自动开始监控
   * @param {boolean} options.reportToServer - 是否向服务器报告性能数据
   * @param {string} options.apiEndpoint - 性能数据上报API端点
   * @param {number} options.sampleRate - 采样率（0-1）
   */
  constructor(options = {}) {
    this.options = {
      autoStart: true,
      reportToServer: false,
      apiEndpoint: '/api/metrics/performance',
      sampleRate: 0.1,
      ...options
    };
    
    // 性能指标
    this.metrics = {
      navigation: {},
      resources: [],
      paint: {},
      memory: {},
      interactions: [],
      apiCalls: [],
      errors: []
    };
    
    // 初始化
    if (this.options.autoStart) {
      this.start();
    }
  }
  
  /**
   * 开始监控
   */
  start() {
    // 检查浏览器支持
    if (!window.performance) {
      console.warn('Performance API not supported in this browser');
      return;
    }
    
    // 决定是否采样
    if (Math.random() > this.options.sampleRate) {
      return;
    }
    
    // 监听页面加载完成事件
    window.addEventListener('load', () => this.collectNavigationTiming());
    
    // 监听资源加载
    this.observeResourceTiming();
    
    // 监听绘制事件
    this.observePaintTiming();
    
    // 监听用户交互
    this.observeInteractions();
    
    // 监听内存使用
    this.startMemoryMonitoring();
    
    // 监听错误
    this.observeErrors();
    
    // 监听API调用
    this.monkeyPatchXHR();
    this.monkeyPatchFetch();
    
    console.log('Performance monitoring started');
  }
  
  /**
   * 收集导航计时指标
   */
  collectNavigationTiming() {
    const navigation = performance.getEntriesByType('navigation')[0];
    if (!navigation) return;
    
    this.metrics.navigation = {
      // 关键时间点
      navigationStart: 0,
      fetchStart: navigation.fetchStart,
      domainLookupStart: navigation.domainLookupStart,
      domainLookupEnd: navigation.domainLookupEnd,
      connectStart: navigation.connectStart,
      connectEnd: navigation.connectEnd,
      requestStart: navigation.requestStart,
      responseStart: navigation.responseStart,
      responseEnd: navigation.responseEnd,
      domInteractive: navigation.domInteractive,
      domContentLoadedEventStart: navigation.domContentLoadedEventStart,
      domContentLoadedEventEnd: navigation.domContentLoadedEventEnd,
      domComplete: navigation.domComplete,
      loadEventStart: navigation.loadEventStart,
      loadEventEnd: navigation.loadEventEnd,
      
      // 计算关键指标
      dnsTime: navigation.domainLookupEnd - navigation.domainLookupStart,
      tcpTime: navigation.connectEnd - navigation.connectStart,
      requestTime: navigation.responseStart - navigation.requestStart,
      responseTime: navigation.responseEnd - navigation.responseStart,
      domProcessingTime: navigation.domComplete - navigation.responseEnd,
      domInteractiveTime: navigation.domInteractive - navigation.navigationStart,
      loadTime: navigation.loadEventEnd - navigation.navigationStart,
      timeToFirstByte: navigation.responseStart - navigation.requestStart,
      timeToInteractive: navigation.domInteractive - navigation.navigationStart,
      
      // 页面信息
      url: window.location.href,
      userAgent: navigator.userAgent,
      timestamp: new Date().toISOString()
    };
    
    // 如果配置了上报，则发送数据
    if (this.options.reportToServer) {
      this.reportMetrics('navigation', this.metrics.navigation);
    }
  }
  
  /**
   * 观察资源加载计时
   */
  observeResourceTiming() {
    // 创建性能观察器
    const resourceObserver = new PerformanceObserver((list) => {
      const entries = list.getEntries();
      
      entries.forEach(entry => {
        // 过滤掉导航请求
        if (entry.entryType === 'resource') {
          const resourceMetric = {
            name: entry.name,
            initiatorType: entry.initiatorType,
            startTime: entry.startTime,
            duration: entry.duration,
            transferSize: entry.transferSize,
            decodedBodySize: entry.decodedBodySize,
            timestamp: new Date().toISOString()
          };
          
          this.metrics.resources.push(resourceMetric);
          
          // 如果是关键资源，单独上报
          if (this.isKeyResource(entry.name) && this.options.reportToServer) {
            this.reportMetrics('resource', resourceMetric);
          }
        }
      });
    });
    
    // 开始观察资源加载
    resourceObserver.observe({ entryTypes: ['resource'] });
  }
  
  /**
   * 判断是否为关键资源
   * @param {string} url - 资源URL
   * @returns {boolean} 是否为关键资源
   */
  isKeyResource(url) {
    // 判断是否为关键JS或CSS
    return (
      url.includes('main') || 
      url.includes('vendor') || 
      url.includes('critical')
    );
  }
  
  /**
   * 观察绘制计时
   */
  observePaintTiming() {
    // 创建性能观察器
    const paintObserver = new PerformanceObserver((list) => {
      const entries = list.getEntries();
      
      entries.forEach(entry => {
        // 记录FP和FCP
        if (entry.name === 'first-paint') {
          this.metrics.paint.firstPaint = entry.startTime;
        } else if (entry.name === 'first-contentful-paint') {
          this.metrics.paint.firstContentfulPaint = entry.startTime;
        }
      });
      
      // 如果已收集到FP和FCP，则上报
      if (this.metrics.paint.firstPaint && this.metrics.paint.firstContentfulPaint && this.options.reportToServer) {
        this.reportMetrics('paint', this.metrics.paint);
      }
    });
    
    // 开始观察绘制事件
    paintObserver.observe({ entryTypes: ['paint'] });
    
    // 监听LCP (Largest Contentful Paint)
    const lcpObserver = new PerformanceObserver((list) => {
      const entries = list.getEntries();
      // 取最后一个LCP条目
      const lastEntry = entries[entries.length - 1];
      
      if (lastEntry) {
        this.metrics.paint.largestContentfulPaint = lastEntry.startTime;
        
        if (this.options.reportToServer) {
          this.reportMetrics('lcp', { largestContentfulPaint: lastEntry.startTime });
        }
      }
    });
    
    lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] });
    
    // 监听CLS (Cumulative Layout Shift)
    let cumulativeLayoutShift = 0;
    const clsObserver = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        // 只有不涉及用户输入的布局偏移才计入CLS
        if (!entry.hadRecentInput) {
          cumulativeLayoutShift += entry.value;
        }
      }
      
      this.metrics.paint.cumulativeLayoutShift = cumulativeLayoutShift;
      
      if (this.options.reportToServer) {
        this.reportMetrics('cls', { cumulativeLayoutShift });
      }
    });
    
    clsObserver.observe({ entryTypes: ['layout-shift'] });
  }
  
  /**
   * 监控内存使用
   */
  startMemoryMonitoring() {
    // 检查是否支持内存API
    if (performance.memory) {
      // 每30秒采集一次内存数据
      this.memoryInterval = setInterval(() => {
        this.metrics.memory = {
          jsHeapSizeLimit: performance.memory.jsHeapSizeLimit,
          totalJSHeapSize: performance.memory.totalJSHeapSize,
          usedJSHeapSize: performance.memory.usedJSHeapSize,
          timestamp: new Date().toISOString()
        };
        
        if (this.options.reportToServer) {
          this.reportMetrics('memory', this.metrics.memory);
        }
      }, 30000);
    }
  }
  
  /**
   * 观察用户交互
   */
  observeInteractions() {
    // 监听点击事件
    document.addEventListener('click', (event) => {
      const target = event.target;
      const interaction = {
        type: 'click',
        targetTag: target.tagName,
        targetId: target.id,
        targetClass: target.className,
        timestamp: new Date().toISOString(),
        path: window.location.pathname
      };
      
      this.metrics.interactions.push(interaction);
    }, { passive: true });
    
    // 监听页面可见性变化
    document.addEventListener('visibilitychange', () => {
      const visibilityState = document.visibilityState;
      const interaction = {
        type: 'visibility',
        state: visibilityState,
        timestamp: new Date().toISOString(),
        path: window.location.pathname
      };
      
      this.metrics.interactions.push(interaction);
      
      if (this.options.reportToServer) {
        this.reportMetrics('visibility', interaction);
      }
    });
  }
  
  /**
   * 监控XHR请求
   */
  monkeyPatchXHR() {
    const originalOpen = XMLHttpRequest.prototype.open;
    const originalSend = XMLHttpRequest.prototype.send;
    const self = this;
    
    XMLHttpRequest.prototype.open = function(method, url) {
      this._perfData = {
        method,
        url,
        startTime: performance.now()
      };
      originalOpen.apply(this, arguments);
    };
    
    XMLHttpRequest.prototype.send = function() {
      if (this._perfData) {
        const apiCall = this._perfData;
        
        this.addEventListener('load', function() {
          apiCall.endTime = performance.now();
          apiCall.duration = apiCall.endTime - apiCall.startTime;
          apiCall.status = this.status;
          apiCall.timestamp = new Date().toISOString();
          
          self.metrics.apiCalls.push(apiCall);
          
          if (self.options.reportToServer && apiCall.duration > 1000) {
            // 只上报慢请求
            self.reportMetrics('apiCall', apiCall);
          }
        });
        
        this.addEventListener('error', function() {
          apiCall.endTime = performance.now();
          apiCall.duration = apiCall.endTime - apiCall.startTime;
          apiCall.status = 'error';
          apiCall.timestamp = new Date().toISOString();
          
          self.metrics.apiCalls.push(apiCall);
          self.metrics.errors.push({
            type: 'xhr',
            url: apiCall.url,
            method: apiCall.method,
            timestamp: apiCall.timestamp
          });
          
          if (self.options.reportToServer) {
            self.reportMetrics('apiError', apiCall);
          }
        });
      }
      
      originalSend.apply(this, arguments);
    };
  }
  
  /**
   * 监控Fetch请求
   */
  monkeyPatchFetch() {
    const originalFetch = window.fetch;
    const self = this;
    
    window.fetch = function(input, init) {
      const startTime = performance.now();
      const method = init && init.method ? init.method : 'GET';
      const url = typeof input === 'string' ? input : input.url;
      
      const apiCall = {
        method,
        url,
        startTime,
        timestamp: new Date().toISOString()
      };
      
      return originalFetch.apply(this, arguments)
        .then(response => {
          apiCall.endTime = performance.now();
          apiCall.duration = apiCall.endTime - apiCall.startTime;
          apiCall.status = response.status;
          
          self.metrics.apiCalls.push(apiCall);
          
          if (self.options.reportToServer && apiCall.duration > 1000) {
            // 只上报慢请求
            self.reportMetrics('apiCall', apiCall);
          }
          
          return response;
        })
        .catch(error => {
          apiCall.endTime = performance.now();
          apiCall.duration = apiCall.endTime - apiCall.startTime;
          apiCall.status = 'error';
          
          self.metrics.apiCalls.push(apiCall);
          self.metrics.errors.push({
            type: 'fetch',
            url: apiCall.url,
            method: apiCall.method,
            timestamp: apiCall.timestamp,
            message: error.message
          });
          
          if (self.options.reportToServer) {
            self.reportMetrics('apiError', apiCall);
          }
          
          throw error;
        });
    };
  }
  
  /**
   * 观察JavaScript错误
   */
  observeErrors() {
    // 监听全局错误
    window.addEventListener('error', (event) => {
      const error = {
        type: 'js',
        message: event.message,
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno,
        timestamp: new Date().toISOString(),
        path: window.location.pathname
      };
      
      this.metrics.errors.push(error);
      
      if (this.options.reportToServer) {
        this.reportMetrics('error', error);
      }
    });
    
    // 监听未捕获的Promise错误
    window.addEventListener('unhandledrejection', (event) => {
      const error = {
        type: 'promise',
        message: event.reason ? (event.reason.message || String(event.reason)) : 'Promise rejected',
        timestamp: new Date().toISOString(),
        path: window.location.pathname
      };
      
      this.metrics.errors.push(error);
      
      if (this.options.reportToServer) {
        this.reportMetrics('error', error);
      }
    });
  }
  
  /**
   * 向服务器报告指标
   * @param {string} type - 指标类型
   * @param {Object} data - 指标数据
   */
  reportMetrics(type, data) {
    if (!this.options.reportToServer) return;
    
    const payload = {
      type,
      data,
      url: window.location.href,
      timestamp: new Date().toISOString(),
      userAgent: navigator.userAgent
    };
    
    // 使用Beacon API进行非阻塞上报
    if (navigator.sendBeacon) {
      navigator.sendBeacon(this.options.apiEndpoint, JSON.stringify(payload));
    } else {
      // 回退到fetch
      fetch(this.options.apiEndpoint, {
        method: 'POST',
        body: JSON.stringify(payload),
        headers: {
          'Content-Type': 'application/json'
        },
        // 使用keepalive确保请求在页面卸载后仍能完成
        keepalive: true
      }).catch(e => console.error('Failed to report metrics:', e));
    }
  }
  
  /**
   * 获取所有收集的指标
   * @returns {Object} 所有性能指标
   */
  getAllMetrics() {
    return {
      ...this.metrics,
      timestamp: new Date().toISOString(),
      url: window.location.href,
      userAgent: navigator.userAgent
    };
  }
  
  /**
   * 停止监控
   */
  stop() {
    // 清除内存监控定时器
    if (this.memoryInterval) {
      clearInterval(this.memoryInterval);
    }
    
    // 上报最终数据
    if (this.options.reportToServer) {
      this.reportMetrics('summary', this.getAllMetrics());
    }
    
    console.log('Performance monitoring stopped');
  }
}

// 导出性能监控器
export default PerformanceMonitor;

// 创建默认实例
export const performanceMonitor = new PerformanceMonitor({
  autoStart: true,
  reportToServer: false,  // 默认不上报，需要时可以开启
  sampleRate: 0.1  // 10%的用户会被采样
});